#pragma once

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <functional>
#include "Log.hpp"
#include "InetAddr.hpp"

using namespace LogMudule;

static const int gsocketfd = -1;
static const uint16_t dafault_prot = 8080;
static const int gsize = 1024;
using func_t = std::function<std::string(const std::string&)>;

class UdpServer
{
public:
    UdpServer(func_t handle, uint16_t prot = dafault_prot)
        : _prot(prot)
        ,_addr(prot)
        ,_handle(handle)
    {
    }

    // 初始化服务器
    void InitServer()
    {
        // 1.创建socket文件描述符
        _socketfd = ::socket(AF_INET, SOCK_DGRAM, 0);
        if (_socketfd < 0)
        {
            LOG(LogLevel::ERROR) << "socket error...";
        }

        LOG(LogLevel::DEBUG) << "socket:"<<_socketfd;
        
        // 2进行绑定
        int n = ::bind(_socketfd, _addr.GetAddr(), _addr.Addr_size());
        if (n < 0)
        {
            LOG(LogLevel::ERROR) << "bind error...";
        }

         LOG(LogLevel::DEBUG) << "绑定成功";
    }

    // 开始
    void Start()
    {
        LOG(LogLevel::DEBUG) << "启动服务器";
        while (true)
        {
            // 1.接受数据
            char buffer[gsize];
            struct sockaddr_in client_addr;
            socklen_t client_size = sizeof(client_addr);
            InetAddr client_tmp(client_addr); 
            int n = ::recvfrom(_socketfd, buffer, gsize - 1, 0, client_tmp.GetAddr(), &client_size);
            if (n < 0)
            {
                LOG(LogLevel::ERROR) << "recvfrom error...";
            }

            buffer[n] = 0;
            LOG(LogLevel::DEBUG) << "读取到数据：" << buffer;

            //2. 对请求进行处理
            std::string ret = _handle(buffer);
            LOG(LogLevel::DEBUG) << "处理后的数据：" << ret;
            //3. 回复
            n = ::sendto(_socketfd, ret.c_str(), ret.size(), 0,  client_tmp.GetAddr(), sizeof(client_addr));
            if (n < 0)
            {
                LOG(LogLevel::ERROR) << "sendto error...";
            }

        }
    }

    ~UdpServer()
    {
        int n = ::close(_socketfd);
        (void)n;
    }

private:
    uint16_t _prot; // 端口号
    int _socketfd; // 文件描述符
    InetAddr _addr;
    func_t _handle; //处理方法 将中文转换成英文
};
